/*  
 * Actipro Software's WPF Docking & MDI / Prism Integration Add-on
 * http://actipro.codeplex.com/
 * 
 * Copyright (c) 2009-2015 Actipro Software LLC. 
 *  
 * This source code is subject to the terms of the Microsoft Public License (Ms-PL). 
 *  
 * Redistribution and use in source and binary forms, with or without modification, 
 * is permitted provided that redistributions of the source code retain the above 
 * copyright notices and this file header. 
 *  
 * Additional copyright notices should be appended to the list above. 
 * 
 * For details, see <http://www.opensource.org/licenses/ms-pl.html>. 
 *  
 * All other rights reserved. 
 *
 */  

using System;
using System.Windows;
using System.Windows.Controls;
using ActiproSoftware.Windows.Controls.Docking;

namespace ActiproSoftware.Windows.Prism.Regions {

	/// <summary>
	/// Represents an implementation of <see cref="IDockingWindowInitializer"/> for tool items.
	/// </summary>
	public class ToolWindowInitializer : DockingWindowInitializer {

		#region Dependency Properties

		/// <summary>
		/// Identifies the <see cref="CanAutoHide"/> dependency property.  This field is read-only.
		/// </summary>
		/// <value>The identifier for the <see cref="CanAutoHide"/> dependency property.</value>
		public static readonly DependencyProperty CanAutoHideProperty = DependencyProperty.Register("CanAutoHide",
			typeof(bool?), typeof(ToolWindowInitializer), new FrameworkPropertyMetadata(null));

		/// <summary>
		/// Identifies the <see cref="CanBecomeDocument"/> dependency property.  This field is read-only.
		/// </summary>
		/// <value>The identifier for the <see cref="CanBecomeDocument"/> dependency property.</value>
		public static readonly DependencyProperty CanBecomeDocumentProperty = DependencyProperty.Register("CanBecomeDocument",
			typeof(bool?), typeof(ToolWindowInitializer), new FrameworkPropertyMetadata(null));

		/// <summary>
		/// Identifies the <see cref="IsInitiallyAutoHidden"/> dependency property.  This field is read-only.
		/// </summary>
		/// <value>The identifier for the <see cref="IsInitiallyAutoHidden"/> dependency property.</value>
		public static readonly DependencyProperty IsInitiallyAutoHiddenProperty = DependencyProperty.Register("IsInitiallyAutoHidden",
			typeof(bool), typeof(DockingWindowInitializer), new FrameworkPropertyMetadata(false));

		#endregion // Dependency Properties

		/////////////////////////////////////////////////////////////////////////////////////////////////////
		#region NON-PUBLIC PROCEDURES
		/////////////////////////////////////////////////////////////////////////////////////////////////////

		/// <summary>
		/// Gets the first <see cref="ToolWindow"/> associated with the specified dock group.
		/// </summary>
		/// <param name="dockSite">The dock site.</param>
		/// <param name="dockGroup">The dock group to find.</param>
		/// <returns>
		/// A <see cref="ToolWindow"/>; otherwise, <see langword="null"/>.
		/// </returns>
		private static ToolWindow GetToolWindow(DockSite dockSite, string dockGroup) {
			if (dockSite != null && !string.IsNullOrEmpty(dockGroup)) {
				foreach (ToolWindow toolWindow in dockSite.ToolWindows) {
					// 1/28/2011 - Added check to ensure ToolWindow is open, since it cannot be a dock target if it's closed (1E6-14D5A07C-FFC5)
					if (toolWindow.IsContainerForItem && toolWindow.IsOpen) {
						ToolWindowInitializer provider = DockSiteRegionAdapter.GetDockingWindowInitializer(toolWindow.DataContext ?? toolWindow) as ToolWindowInitializer;
						if (provider != null && provider.DefaultDockGroup == dockGroup)
							return toolWindow;
					}
				}
			}
			return null;
		}

		/// <summary>
		/// Open the specified tool window.
		/// </summary>
		/// <param name="toolWindow">The tool window to open.</param>
		private void OpenToolWindow(ToolWindow toolWindow) {
			// 1/28/2011 - Updated code to immediately auto-hide ToolWindow, instead of docking then auto-hiding to better support grouping in auto-hide state
			if (toolWindow == null)
				return;

			DockSite dockSite = toolWindow.DockSite;
			if (dockSite == null)
				return;

			// First, try to dock to dock group
			string group = this.DefaultDockGroup;
			if (!string.IsNullOrEmpty(group)) {
				ToolWindow targetToolWindow = GetToolWindow(dockSite, group);
				if (targetToolWindow != null && targetToolWindow != toolWindow) {
					toolWindow.Dock(targetToolWindow, Direction.Content);
					return;
				}
			}

			Dock? direction = this.DefaultDockDirection;
			if (direction != null) {
				// Second, try to dock relative to group
				string relativeGroup = this.DefaultDockRelativeGroup;
				if (!string.IsNullOrEmpty(relativeGroup)) {
					ToolWindow targetToolWindow = GetToolWindow(dockSite, relativeGroup);
					if (targetToolWindow != null && targetToolWindow != toolWindow) {
						toolWindow.Dock(targetToolWindow, direction.Value);
						return;
					}
				}

				// Third, dock relative to dock site
				if (this.IsInitiallyAutoHidden && toolWindow.CanAutoHideResolved)
					toolWindow.AutoHide(direction.Value);
				else
					toolWindow.Dock(dockSite, direction.Value);
				return;
			}

			// Last, open in default dock location
			if (this.IsInitiallyAutoHidden && toolWindow.CanAutoHideResolved)
				toolWindow.AutoHide();
			else
				toolWindow.Dock();
		}

		#endregion // NON-PUBLIC PROCEDURES

		/////////////////////////////////////////////////////////////////////////////////////////////////////
		#region PUBLIC PROCEDURES
		/////////////////////////////////////////////////////////////////////////////////////////////////////

		/// <summary>
		/// Gets or sets whether the associated tool window may be placed in auto-hide mode.
		/// This is a dependency property.
		/// </summary>
		/// <value>
		/// A nullable <see cref="Boolean"/> that indicates whether the associated tool window may be placed in auto-hide mode.
		/// The default value is <see langword="null"/>.
		/// </value>
		/// <remarks>
		/// If set to <see langword="null"/>, the resolved value will use the global <see cref="DockSite"/> setting.
		/// </remarks>
		public bool? CanAutoHide {
			get { return (bool?)this.GetValue(CanAutoHideProperty); }
			set { this.SetValue(CanAutoHideProperty, value); }
		}

		/// <summary>
		/// Gets or sets whether the associated tool window may be placed in a document state.
		/// This is a dependency property.
		/// </summary>
		/// <value>
		/// A nullable <see cref="Boolean"/> that indicates whether the associated tool window may be placed in a document state.
		/// The default value is <see langword="null"/>.
		/// </value>
		/// <remarks>
		/// If set to <see langword="null"/>, the resolved value will use the global <see cref="DockSite"/> setting.
		/// </remarks>
		public bool? CanBecomeDocument {
			get { return (bool?)this.GetValue(CanBecomeDocumentProperty); }
			set { this.SetValue(CanBecomeDocumentProperty, value); }
		}

		/// <summary>
		/// Creates a new instance of the <see cref="ToolWindowInitializer"/> class.
		/// </summary>
		/// <returns>The new instance.</returns>
		protected override Freezable CreateInstanceCore() {
			return new ToolWindowInitializer();
		}

		/// <summary>
		/// Gets the docking window item type of the specified item.
		/// </summary>
		/// <param name="item">The item.</param>
		/// <returns>
		/// A <see cref="DockingWindowItemType"/> value.
		/// </returns>
		public override DockingWindowItemType GetDockingWindowItemType(object item) {
			return DockingWindowItemType.Tool;
		}

		/// <summary>
		/// Initializes the specified docking window with any associated metadata.
		/// </summary>
		/// <param name="dockingWindow">The docking window that should be initialized.</param>
		/// <param name="item">The associated item.</param>
		public override void Initialize(DockingWindow dockingWindow, object item) {
			// Call base method
			base.Initialize(dockingWindow, item);

			ToolWindow toolWindow = dockingWindow as ToolWindow;
			if (toolWindow != null) {
				// Bind properties
				this.BindProperty(CanAutoHideProperty, toolWindow, ToolWindow.CanAutoHideProperty);
				this.BindProperty(CanBecomeDocumentProperty, toolWindow, ToolWindow.CanBecomeDocumentProperty);
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance is initially auto hidden.
		/// This is a dependency property.
		/// </summary>
		/// <value>
		/// <c>true</c> if this instance is initially auto hidden; otherwise, <c>false</c>.
		/// The default value is <c>false</c>.
		/// </value>
		public bool IsInitiallyAutoHidden {
			get { return (bool)this.GetValue(IsInitiallyAutoHiddenProperty); }
			set { this.SetValue(IsInitiallyAutoHiddenProperty, value); }
		}

		/// <summary>
		/// Opens the specified docking window with any associated metadata.
		/// </summary>
		/// <param name="dockingWindow">The docking window that should be opened.</param>
		/// <param name="item">The associated item.</param>
		public override void Open(DockingWindow dockingWindow, object item) {
			ToolWindow toolWindow = dockingWindow as ToolWindow;
			if (toolWindow != null)
				this.OpenToolWindow(toolWindow);
			else
				base.Open(dockingWindow, item);
		}

		#endregion // PUBLIC PROCEDURES
	}
}